//==============================================================================
// HashSamplingOverlapper.hh
//
// ----------------------------------------------------------------------------
// $Id: $
//------------------------------------------------------------------------------
// $Log: $
//
//==============================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8
//search engine data structure of reads)

#ifndef _HASH_SAMPLING_OVERLAPPER
#define _HASH_SAMPLING_OVERLAPPER

#include "LocalSTL.hh"
#include "Sequence.hh"
#include "RandomNumberGenerator.hh"
#include "SearchResult.hh"
#include "SuffixTree.hh"
#include "AdjacencyListGraph.hh"
#include "SeqSampler.hh"
#include "CLibraryAdditions.hh"
#include "HashSampleSearchEngine.hh"

//----------------------------------------------------------------------
// * StatHash
//----------------------------------------------------------------------
//
// A hash for storing simple statistics about hits. Note that 
// in many places this hash is used with array syntax, for example:
// h[i]++ 
// looks up entry with key i, increments it's value, and stores it
// back into the hash.  It looks like array access, but it's a hash
// access. 
// 
// CAUTION:  This similarity with arrays is misleading.  For 
// example:
//
// if(h[i] == 0)  
//
// will ALWAYS create an entry (i,0) in h!!!  Must use Contains
// to test for existence of a value.  
//
class StatHash : public hash_map<int,int,hash<int>,equal_to<int> >{
public:

  bool Contains(int key){
	 const StatHash::iterator it = find(key);
	 if (it != end()) return(true);
	 else return(false);
  }

  bool Lookup(int key,int &value){
	 const StatHash::iterator it = find(key);
	 if (it != end()){
		value = (*it).second;
		return(true);
	 }
	 return(false);
  }

  bool Add(int key,int value){	 
	 insert(value_type(key,value));
  }  
};

//----------------------------------------------------------------------
// * SampleHitStats
//----------------------------------------------------------------------
//
class SampleHitStats{
public:
  vector<int> mTotalHitsBySample;
  StatHash mTotalHitsOnSource;
  StatHash mLastHitOnSource;

  StatHash mIntervalHitsOnSource;
  StatHash mIntervalSpanOnSource;

  void Clear(){
	 mTotalHitsBySample.clear();
	 mTotalHitsOnSource.clear();
	 mLastHitOnSource.clear();

	 mIntervalHitsOnSource.clear();
	 mIntervalSpanOnSource.clear();
  }

  void InitSampleStats(int NumSamples){
	 mTotalHitsBySample.resize(NumSamples);
	 for(int i = 0;i<NumSamples;i++) mTotalHitsBySample[i]=0;
  }

  // Mainly for DEBUGGING
  long mRepeatFilterCount;
};

#if 0
class SampleHitStats{
public:

  SampleHitStats(){
	 mSize = 0;
	 mSSize = 0;
  }

  int * mTotalHitsBySample; 
  int * mTotalHitsOnSource;
  int * mLastHitOnSource;  // Used for filter interior singleton heuristic.

  int * mIntervalHitsOnSource;
  int * mIntervalSpanOnSource;
 
  long mSize;
  long mSSize;
 
  // Mainly for DEBUGGING
  long mRepeatFilterCount;
 
}; 
#endif

//-----------------------------------------------------------------------------
// * HashSamplingOverlapper
//-----------------------------------------------------------------------------
// 
class HashSamplingOverlapper{
public:

  SequenceVector *mpQueries;
  int mFirstQuery;
  int mLastQuery;
  int mSamplesPerKbp;
  int mSampleSpacing;
  int mSampleSize;

  SequenceVector *mpSources;
  int  mNumSourceGroups;
  int  mSourcesInGroup;
  int mSourceStart;  // The first source in the current group
  int mSourceEnd;    // The last source in the current group 
 
  int mMinOverlapForGraph;

  // Stats for the hit rate for samples.  These stats are used
  // to determine which samples are some kind of repeat.  The mean 
  // sources hit by Samples is an estimate of the depth of coverage. 
  float mMeanHitsPerSample;
  float mStDevHitsPerSample;

  float mStDevRepeatCutoff;
  int   mRepeatThreshold;

  // Statistics for both forward and reverse compilment samples. 
  SampleHitStats FwdStats;
  SampleHitStats RevStats;


  // Heuristics to use
  bool mbFilterInteriorSingletons;

  // DEBUGGING
  Table<int> *mpTrueOverlaps;

  HashSamplingOverlapper(){ 
	 mStDevRepeatCutoff = 10;
  };

  void ComputeSourceGroupSizes();
  void InitSourceStatVectors(int NumSources,int NumSamples,SampleHitStats &Stats);
  void ClearSourceStatVectors(SampleHitStats &Stats);

  // Oversee operation
  void ComputeOverlapGraph(AdjacencyListGraph &OverlapGraph);
 
  // Repeat statistics that are used for repeat filtering. 
  void ComputeGlobalRepeatStatistics(SequenceVector &Queries,
												 HashSampleSearchEngine &CST);

  // Compute the overlaps for a single query.   
  void ComputeOverlapsForQuery(int QIdx,HashSampleSearchEngine &HS,
										 SequenceVector &QuerySamples,
										 AdjacencyListGraph &OverlapGraph);

  // Compute statistics about the kind and number of sample hits across
  // all of the sources.  
  void ComputeSampleHitStats(SampleSearchResultVec &SearchResults,SampleHitStats &Stats);

  void ComputeHitsAndIntervalHitsOnSources(SampleSearchResultVec &SearchResults,
														 SampleHitStats &Stats);
  void FilterInteriorSingletons(SampleHitStats &Stats);


  // Use the hit statistics to come up with an overlap estimate for 
  // each source against one query. 
  void EstimateOverlaps(vector<float> &Overlaps,SampleHitStats &Fwd,SampleHitStats &Rev);
  void ConvertOverlapsToFraction(vector<float> &Ovrlaps,SequenceVector &Seqs);

  // Add a vector of source overlap estimates to the overlap graph. 
  void AddToGraph(int QueryIdx,vector<float> &SourceOverlaps,
						AdjacencyListGraph &OverlapGraph);




  // OLD/DEBUG  ===========================================================

  void PlotSampleHits(ostream &fout,int NumSamples,string &QueryName,
							 SequenceVector &Sources, SampleSearchResultVec &Results);

  void PlotSampleHits2(ostream &fout,int NumSamples,int QIdx,
							  SequenceVector &Queries,
							  SequenceVector &Sources, SampleSearchResultVec &Results,
							  Table<int> &TrueOverlaps,vector<float> &PredictedOverlaps);
  
  void PrintHitDistribution(ostream &fout,vector<int> &Values,float mean,float stDev);
  

  // Create Samples
  void AddReverseCompliment(Sequence &Seq,SequenceVector &SeqVec);
  void SampleQuery(Sequence &QueryIn,SequenceVector &SamplesOut);
  
  void CreateQuerySamples(vector<SequenceVector> &QuerySamples);


  void ComputePerfectSensitivityGraph(AdjacencyListGraph &OverlapGraph);

  void ComputePerfectSensitivityOverlapsForQuery(int QueryIdx,
																 HashSampleSearchEngine &HE,
																 SequenceVector &QuerySamples,
																 AdjacencyListGraph &OverlapGraph);

  void ComputeUnfilteredHitsAndIntervalHitsOnSources(SampleSearchResultVec 
																	  &SearchResults);

  void ComputeHitsAndIntervalHitsOnSources2(SampleSearchResultVec &SearchResults);
  void ComputeHitsAndIntervalHitsOnSources3(SampleSearchResultVec &SearchResults);
  void ComputeHitsOnSources(SampleSearchResultVec &SearchResults);
  


};



#endif
